<?php
declare (strict_types=1);

namespace app\common\queue\upload;

use app\admin\logic\system\Config as SystemConfig;
use app\admin\logic\system\Message;
use app\common\event\subscribes\attach\Attach as AttachSubscribes;
use app\common\exception\LogicException;
use app\common\helper\util\Tool;
use app\common\library\Queue;
use app\common\model\Attach;
use app\common\service\BaseService;
use eduline\upload\Client as FileClient;
use eduline\upload\utils\Util;
use Exception;
use Nette\Utils\Json;
use Nette\Utils\JsonException;
use think\facade\Db;
use think\facade\Event;
use think\facade\Request;

// use think\facade\Log;

/**
 * Class SyncToLocal
 *
 * @package app\common\queue\upload
 */
class SyncVideoToLocal
{
    /**
     * @var String
     */
    private $stock;

    /**
     * @var integer
     */
    private $adminUserId;

    public function run()
    {
        $post = Request::post();

        $this->stock       = (string)$post['fromStock'];
        $this->adminUserId = intval($post['adminUserId']);

        // 腾讯使用本地上传方式同步
        if ($this->stock === 'tencent') {
            $this->handlerTencentSync(intval($post['attach_id']));

            return BaseService::parseToData([], 1);
        }

        $params = [
            // 开始页数
            'pageNo'      => intval($post['pageNo']) ?: 1,
            // 每页大小
            'pageSize'    => intval($post['pageSize']) ?: 10,
            // 结束页
            'endPage'     => intval($post['endPage']) ?: 0,
            // 本次任务累计同步数量
            'count'       => intval($post['count']) ?: 0,
            // 需要同步的云端
            'fromStock'   => $this->stock,
            // 机构id
            'mhmId'       => intval($post['mhmId']),
            // 操作的用户id
            'adminUserId' => $this->adminUserId
        ];

        // Log::write(sprintf('视频同步到本地[%s]', Json::encode($params)));
        // 检测是否使用了平台配置
        $this->checkUsePlatform($params['mhmId']);
        // 同步
        $this->handlerSync($params);

        return BaseService::parseToData([], 1);
    }

    /**
     * 检测是否启用了平台配置
     *
     * @param $mhmId
     */
    private function checkUsePlatform($mhmId)
    {
        // 检测是否配置了自己的储存空间
        $config = SystemConfig::get('system.package.upload.sync', [], $mhmId);
        // 是否设置了使用平台配置
        if ($mhmId != 1 && isset($config['use_platform']) && $config['use_platform'] === 1) {
            // Log::write(sprintf('机构[%d]使用了平台配置，已停止同步', $mhmId));
            $this->handlerSendErrorMessage('使用了平台配置，同步失败');
            throw new LogicException('使用了平台配置，已停止同步');
        }
    }

    /**
     * 处理同步，通用方法
     *
     * @param array $params
     */
    private function handlerSync(array $params)
    {
        $stock  = $this->stock;
        $client = new FileClient($stock);
        $result = $client->getVideoList($this->handlerParams($params));
        $videos = $result['video_list'] ?? [];
        $total  = $result['total'] ?? 0;

        // 执行处理
        $count = $this->handlerSaveData($videos);

        // 累计成功条数
        $params['count'] = $params['count'] + $count;

        // 是否有更多页
        $totalPage = ceil($total / $params['pageSize']);

        // Log::write(sprintf('视频同步到本地计算是否有下一页参数[%s]', Json::encode([
        //     'count'     => $count,
        //     'total'     => $total,
        //     'totalPage' => $totalPage
        // ])));

        // 是否继续同步
        // 条件1: 未指定结束页,且存在下一页
        $condition = $params['endPage'] == 0 && $params['pageNo'] < $totalPage;
        // 条件2:  指定了结束页,结束页 > 当前页,且存在下一页
        $conditionTwo = $params['endPage'] > 0 && $params['endPage'] > $params['pageNo'] && $params['pageNo'] < $totalPage;
        //
        // Log::write(sprintf('视频同步到本地计算是否有下一页结果[%s]', Json::encode([
        //     'condition'    => $condition,
        //     'conditionTwo' => $conditionTwo
        // ])));
        if ($condition || $conditionTwo) {
            // 推送下一个同步任务
            $params['pageNo'] += 1;
            // 推送同步任务
            Queue::push('SyncVideoToLocal', $params);
        } else {
            $this->handlerSendMessage($params['count']);
        }
    }

    /**
     * 处理腾讯云点播导入的数据
     *
     * @param int $attachId
     * @throws JsonException
     */
    private function handlerTencentSync(int $attachId)
    {
        $datas    = [];
        $filepath = Attach::where('id', $attachId)->findOrEmpty()->getAttr('filepath');
        // 读取文件内容
        if (file_exists($filepath)) {
            $file = fopen($filepath, "r");

            while (!feof($file)) {
                $datas[] = fgets($file);
            }

            fclose($file);
        }

        if (!empty($datas)) {
            // 分组
            // $rows = array_chunk($datas,200);
            $videos = [];
            foreach ($datas as $dataStr) {
                if ($dataStr != '') {
                    $videos[] = Json::decode($dataStr, JSON_OBJECT_AS_ARRAY);
                }
            }

            $count = $this->handlerSaveData($videos);

            $this->handlerSendMessage($count);

            // 删除附件
            Event::subscribe(AttachSubscribes::class);
            Event::trigger('AttachTrueDeleted', $attachId);
        }
    }

    /**
     * 取得videoid标识 - 第三方储存的key
     *
     * @param array $video
     * @return mixed|string
     */
    private function getVideoId(array $video)
    {
        $videoId = '';
        switch ($this->stock) {
            case 'aliyun':
                $videoId = $video['VideoId'];
                break;
            case 'bokecc':
                $videoId = $video['id'];
                break;
            case 'tencent':
                $videoId = $video['vid'];
                break;
        }

        return $videoId;
    }

    /**
     * 从video信息中整理attach数据
     *
     * @param array $video
     * @return array
     * @return array attach 附件数据
     * @return array attach_type 附件类型 2: 音频 3: 视频
     */
    private function getAttachDataByStock(array $video): array
    {
        $save = [
            'stock'    => $this->stock,
            'to_stock' => $this->stock,
            'filehash' => '',
            'filemd5'  => '',
            'status'   => 1,
            'from'     => 'pc'
        ];
        switch ($this->stock) {
            case 'aliyun':

                $save = array_merge($save, [
                    'bucket'    => '',
                    'savename'  => $video['VideoId'],
                    'filename'  => $video['Title'],
                    'mimetype'  => 'video/mp4',
                    'extension' => 'mp4',
                    'cover_url' => $video['CoverURL'],
                    'duration'  => floor($video['Duration']),
                    'filesize'  => $video['Size'],

                ]);
                break;
            case 'bokecc':
                $filesize = $video['originalsize'] ?? 0;
                if ($filesize == 0) {
                    // 获取第一个
                    $definition = current($video['definition']);
                    $filesize   = $definition['filesize'] ?? 0;
                }
                $save = array_merge($save, [
                    'bucket'    => $this->stock,
                    'savename'  => $video['id'],
                    'filename'  => $video['title'] . '.mp4',
                    'mimetype'  => 'video/mp4',
                    'extension' => 'mp4',
                    'cover_url' => $video['image'],
                    'duration'  => $video['duration'],
                    'filesize'  => $filesize,
                ]);
                break;
            case 'tencent':
                $save = array_merge($save, [
                    'bucket'    => $this->stock,
                    'savename'  => $video['vid'],
                    'filename'  => $video['name'],
                    'mimetype'  => $video['format'] === 'mp4' ? 'video/mp4' : 'audio/mpeg',
                    'extension' => $video['format'],
                    'cover_url' => $video['coverUrl'],
                    'duration'  => strtotime('1970-01-01 ' . $video['duration'] . 'GMT'),
                    'filesize'  => Tool::stringSizeToBytes($video['size']),
                ]);
                break;
        }

        // 根据后缀名检测音视频类型
        $extension         = substr(strrchr($save['filename'], '.'), 1);
        $save['extension'] = $extension;
        if (Util::isVideo('', $extension)) {
            $mimetype   = 'video/mp4';
            $attachType = 3;
        } else {
            $mimetype   = 'audio/mpeg';
            $attachType = 2;
        }

        $save['mimetype'] = $mimetype;

        return [
            'attach'      => $save,
            'attach_type' => $attachType
        ];
    }

    /**
     *
     * 处理参数
     *
     * @param array $params
     * @return array
     */
    private function handlerParams(array $params)
    {
        if ($this->stock === 'bokecc') {
            $params = [
                'num_per_page' => $params['pageSize'],
                'page'         => $params['pageNo']
            ];
        }

        return $params;
    }

    /**
     * 保存数据
     *
     * @param $videos
     * @return int
     */
    private function handlerSaveData($videos)
    {
        $count = 0;
        foreach ($videos as $video) {
            // 查看是否有视频
            $attach = Attach::where('savename', $this->getVideoId($video))
                ->where('stock', $this->stock)
                ->where('to_stock', $this->stock)
                ->findOrEmpty();
            if (!$attach->isEmpty()) {
                continue;
            }
            Db::startTrans();
            try {
                $attachData = $this->getAttachDataByStock($video);

                $create = Attach::create($attachData['attach']);

                // 上传素材
                $material = [
                    'material_type'        => $attachData['attach_type'] ?? 3,
                    'attach_id'            => $create->id,
                    'material_category_id' => -1,
                    'admin_user_id'        => $params['adminUserId'] ?? 1,
                    'mhm_id'               => $params['mhmId'] ?? 1,
                    'update_time'          => time()
                ];

                $re = Db::name('material')->save($material);
                if ($re) {
                    $count += 1;
                    Db::commit();
                }

            } catch (Exception $exception) {
                Db::rollback();
            }
        }

        return $count;
    }

    /**
     * 发送成功通知消息
     *
     * @param $count
     */
    private function handlerSendMessage($count)
    {
        Message::send(
            sprintf('同步"%s"提醒', $this->getStockName()),
            sprintf('本次成功同步 %s 条数据', $count),
            $this->adminUserId
        );
    }

    /**
     * 发送错误消息
     *
     * @param string $error
     */
    private function handlerSendErrorMessage(string $error)
    {
        Message::send(
            sprintf('同步"%s"提醒', $this->getStockName()),
            sprintf('错误信息： %s', $error),
            $this->adminUserId
        );
    }

    /**
     * 获取储存空间名称
     *
     * @return string
     */
    private function getStockName()
    {
        // 本次同步结束,发送消息通知
        $text = [
            'aliyun'  => '阿里云-云点播',
            'tencent' => '腾讯云-云点播',
            'bokecc'  => 'Bokecc-云点播'
        ];

        return $text[$this->stock] ?? '';
    }
}
